<!DOCTYPE html>
<html>
	<head>
		<meta charset=utf-8>
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<title>My first Three.js app</title>
		<style>
			body { margin: 0; border: 0; padding: 0; width: 100%; height: 100%; overflow: hidden;}
			canvas { width: 100%; height: 100%; }
          #container { width: 100%; height: 80%; display: inline-block; float: left;}
          #console {width: 100%; height: 20%; display: inline-block; float: right;}
          #help { width: 49%; height: 100%; display: inline-block; float: left; overflow:hide; margin: 0; padding: 0; border-right: 1px solid #000;}
          #info { width: 49%; height: 100%; display: inline-block; float: right; overflow-y:scroll;}
          #help ul { list-style: none; margin: 0; padding: 0;}
          #help ul li { list-style: none; width: 45%; display: inline-block;}
		</style>
	</head>
	<body>
      <div id="container"></div>
      <div id="console">
        <div id="help">
          帮助：<br />
          快捷键：<br />
          <ul>
            <li>A\&larr;，逆时针转</li>
            <li>D\&rarr;，顺时针转</li>
            <li>W\&uarr;，放大</li>
            <li>S\&darr;，缩小</li>
            <li>Q，左平移</li>
            <li>E，右平移</li>
            <li>R，上旋</li>
            <li>F，下旋</li>
          </ul>
        </div>
        <div id="info">
          log info: <br />
        </div>
      </div>
      
		<!-- <script src="js/three.min.js"></script> -->
      <script src="../js/three.min.js"></script>
      
      <script src="../js/Detector.js"></script>
      <script src="../js/Stats.js"></script>
      <script src="../js/OrbitControls.js"></script>
      <script src="../js/KeyboardState.js"></script>
      
      <script src="../js/Projector.js"></script>
      
		<script>
			// Our Javascript will go here.
          
          // MAIN

          // standard global variables
          var container = document.getElementById("container");
          var scene, camera, renderer, controls, stats;
          var clock = new THREE.Clock();
          
          var keyboard = new KeyboardState();

          var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight * 0.8; // 

          //var xyz = { x: 0, y: 0, z: 200 };
          
          // custom global variables
          var targetList = [];
          var projector, mouse = { x: 0, y: 0 };
          
          // loginfo
          var info = document.getElementById("info");
          info.style.height = (SCREEN_HEIGHT*0.2)+'px';
          
          function loginfo(log) {
            info.innerHTML += log;
            info.innerHTML += "<br />";
          }
          
          // 定义机柜、服务器数据
          var model = [
            {
              cabinet: 
              {
                'uuid': '1',
                'id': 1, 
                'name':'1号机柜', 
                'size': {w: 30, h: 70, d: 30}, // 尺寸
                'position': {x: 0, y: 0, z: 50}, // 位置
                'servers': [
                  {'uuid': '11', 'id':11, 'name':'1号服务器', 'ip':'', 'apps': ''},
                  {'uuid': '12', 'id':12, 'name':'2号服务器', 'ip':'', 'apps': ''},
                  {'uuid': '13', 'id':13, 'name':'3号服务器', 'ip':'', 'apps': ''},
                  {'uuid': '14', 'id':14, 'name':'4号服务器', 'ip':'', 'apps': ''},
                  {'uuid': '15', 'id':15, 'name':'5号服务器', 'ip':'', 'apps': ''},
                  {'uuid': '16', 'id':16, 'name':'6号服务器', 'ip':'', 'apps': ''},
                  {'uuid': '17', 'id':17, 'name':'7号服务器', 'ip':'', 'apps': ''}
                ]
              }
            },
            {
              cabinet: 
              {
                'uuid': '2',
                'id': 2, 
                'name':'2号机柜', 
                'size': {w: 30, h: 70, d: 30}, // 尺寸 宽、高、深
                'position': {x: 50, y: 0, z: -50}, // 位置
                'servers': [
                  {'uuid': '21', 'id':21, 'name':'', 'ip':'', 'apps': ''}
                ]
              }
            },
            {
              cabinet: 
              {
                'uuid': '3',
                'id': 3, 
                'name':'3号机柜', 
                'size': {w: 30, h: 70, d: 30}, // 尺寸
                'position': {x: -50, y: 0, z: -50}, // 位置
                'servers': [
                  {'uuid': '31', 'id':31, 'name':'', 'ip':'', 'apps': ''}
                ]
              }
            }
          ];
          
          // 处理服务器打开、关闭时，信息的展示和隐藏
          function openServer(o) {
            loginfo('open:'+o.container.info.id+','+o.container.info.name+'--'+o.info.id+','+o.info.name);
          }
          function closeServer(o) {
            loginfo('close:'+o.container.info.id+','+o.container.info.name+'--'+o.info.id+','+o.info.name);
          }
          
          // 处理机柜打开、关闭时，信息的展示和隐藏
          function openCabinet(o) {
            loginfo('open:'+o.info.id+','+o.info.name);
          }
          function closeCabinet(o) {
            loginfo('close:'+o.info.id+','+o.info.name);
          }
          
          // 处理鼠标HHover服务器时，服务器信息的内容渲染
          function hoverServer(o) {
            openHover(o.info.uuid, function() {
              // show info
              loginfo('open:'+o.container.info.id+','+o.container.info.name+'--'+o.info.id+','+o.info.name);
            });
          }
          
          // 处理鼠标HHover机柜时，机柜信息的内容渲染
          function hoverCabinet(o) {
            openHover(o.info.uuid, function() {
              // show info
              loginfo('hover:'+o.info.id+','+o.info.name);
            });
          }
          
          // 鼠标Hover时的通用方法
          var curHoverUUID = null;
          function openHover(hoverUUID, callback) {
            if (curHoverUUID == hoverUUID) return;
            curHoverUUID = hoverUUID;
            
            // 显示Div等操作
            
            // 回调
            callback();
          }
          function closeHover() {
            curHoverUUID = null;
            
            // 隐藏Div等操作
          }
          
          init();
          animate();

          // FUNCTIONS
          function init() {
            // SCENE
            scene = new THREE.Scene();
            
            // CAMERA
            var VIEW_ANGLE = 50, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 2000;
            
            camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
            scene.add(camera);
            camera.position.set(0,200,550);
            camera.lookAt(scene.position);
            
            // camera.position.z = 5;
          
            // RENDERER
            //renderer = new THREE.WebGLRenderer();
            if ( Detector.webgl )
              renderer = new THREE.WebGLRenderer( {antialias:true} );
            else
              renderer = new THREE.CanvasRenderer();

            renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
            container.appendChild( renderer.domElement );
          
            // CONTROLS
            controls = new THREE.OrbitControls( camera, renderer.domElement );
            
            // STATS
            stats = new Stats();
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.top = '0px';
            stats.domElement.style.zIndex = 100;
            container.appendChild( stats.domElement );
            
            // LIGHT
            var light = new THREE.PointLight(0x00ff00);
            light.position.set(0,100,0);
            scene.add(light);
            
            initModel();
            
            // initialize object to perform world/screen calculations
            projector = new THREE.Projector();

            // when the mouse moves, call the given function
            document.addEventListener( 'mousedown', onDocumentMouseDown, false );
            
            // when the mouse moves, call the given function
            document.addEventListener( 'mousemove', onDocumentMouseMove, false );
          }
          
          function initModel() {

            // FLOOR
            createFloor(1024, 800);

            // WALL
            createWall(600, 80, 0, 41, -150, 0, 0, 0);

            createGlassWall(300, 80, 296, 41, 0, 0, Math.PI / 2, 0);
            createGlassWall(300, 80, -296, 41, 0, 0, -Math.PI / 2, 0);

            createGlassWall(100, 80, 296, 41, 210, 0, Math.PI / 2, 0);
            createGlassWall(100, 80, -296, 41, 210, 0, -Math.PI / 2, 0);

            createGlassWall(80, 80, 250, 41, 155, 0, 0, 0);
            createGlassWall(80, 80, -250, 41, 155, 0, 0, 0);

            createGlassWall(300, 80, 0, 41, 155, 0, 0, 0);
            
            createGlassWall(80, 80, 250, 41, 265, 0, 0, 0);
            createGlassWall(80, 80, -250, 41, 265, 0, 0, 0);
            
            createGlassWall(300, 80, 0, 41, 265, 0, 0, 0);
            
            // COLUMN
            createColumn(10, 80, 295, 41, 155);
            createColumn(10, 80, -295, 41, 155);
            createColumn(10, 80, 210, 41, 155);
            createColumn(10, 80, -210, 41, 155);
            createColumn(10, 80, 150, 41, 155);
            createColumn(10, 80, -150, 41, 155);

            createColumn(10, 80, 295, 41, 265);
            createColumn(10, 80, -295, 41, 265);
            createColumn(10, 80, 210, 41, 265);
            createColumn(10, 80, -210, 41, 265);
            createColumn(10, 80, 150, 41, 265);
            createColumn(10, 80, -150, 41, 265);
            
            createFireExtinguisher(8, 30, 285, 16, 140);
            createFireExtinguisher(8, 30, -285, 16, 140);
            
            createStandAir(30, 70, 15, 200, 36, -135);
            createStandAir(30, 70, 15, -200, 36, -135);
            
            var dev1 = createDevice(30, 70, 25, 200, 36, 50, {'color': 0xffff00, 'uuid': 'dev1', 'tooltip': '市电控制柜'});
            dev1.hover = function(o) {
              openHover(o.info.uuid, function() {
                loginfo('hover:'+o.info.tooltip);
              });
            }
            var dev2 = createDevice(30, 70, 25, 200, 36, -50, {'color': 0xff0000, 'uuid': 'dev1', 'tooltip': '强电控制柜'});
            dev2.hover = function(o) {
              openHover(o.info.uuid, function() {
                loginfo('hover:'+o.info.tooltip);
              });
            }
            var dev3 = createDevice(30, 70, 25, 250, 36, 50, {'color': 0xff0000, 'uuid': 'dev1', 'tooltip': '强电控制柜'});
            dev3.hover = function(o) {
              openHover(o.info.uuid, function() {
                loginfo('hover:'+o.info.tooltip);
              });
            }
            var dev4 = createDevice(30, 70, 25, 250, 36, -50, {'color': 0xcccccc, 'uuid': 'dev1', 'tooltip': '空调控制柜'});
            dev4.hover = function(o) {
              openHover(o.info.uuid, function() {
                loginfo('hover:'+o.info.tooltip);
              });
            }

            // WINDOW
            /*
            var windw = createWindow( 245, 50, 0, 41, 180, 0, 0, 0 );
            windw.toggle = function(o) {
              if ( o.rotation.x == 0 ) {
                o.rotation.x = o.rotation.x + Math.PI / 4;
              } else {
                o.rotation.x = o.rotation.x - Math.PI / 4;
              }
            }
            */
            
            // DOOR
            var door_right = createDoor( 50, 80, 180, 41, 265, 0, 0, 0);
            door_right.toggle = function(o) {
              if ( o.rotation.y == 0 ) {
                o.rotation.y = o.rotation.y + Math.PI / 2;
                o.position.x = o.position.x + 25;
                o.position.z = o.position.z + 25;
              } else {
                o.rotation.y = o.rotation.y - Math.PI / 2;
                o.position.x = o.position.x - 25;
                o.position.z = o.position.z - 25;
              }
            }
            //scene.add(door_right);
            //targetList.push(door_right);
            
            var door_left = createDoor( 50, 80, -180, 41, 265, 0, 0, 0);
            door_left.toggle = function(o) {
              if ( o.rotation.y == 0 ) {
                o.rotation.y = o.rotation.y + Math.PI / 2;
                o.position.x = o.position.x - 25;
                o.position.z = o.position.z + 25;
              } else {
                o.rotation.y = o.rotation.y - Math.PI / 2;
                o.position.x = o.position.x + 25;
                o.position.z = o.position.z - 25;
              }
            }
            //scene.add(door_left);
            //targetList.push(door_left);

            // 创建机柜，
            
            for (var i=0; i<model.length; i++) {
              var c = model[i].cabinet;
              createCabinet(c.size.w, c.size.h, c.size.d, c.position.x, c.position.y, c.position.z, c);
            }
            
            //var cabinet = createCabinet(30, 70, 30, 0, 0, 0 );
            
            //var cabinet = createCabinet(30, 70, 30, 50, 0, 0 );
            //var cabinet = createCabinet(30, 70, 30, -50, 0, 0 );
            
            //var cabinet = createCabinet(30, 70, 30, 0, 0, 100 );
            //var cabinet = createCabinet(30, 70, 30, 0, 0, -100 );
          }
          
          function createCabinet(w, h, d, px, py, pz, c) {
            var cabinet = {};
            
            // 机柜的后
            var geometry = new THREE.BoxGeometry(w, h, 2);
            var meterial = new THREE.MeshBasicMaterial( { color: 0x777777, opacity: 0.2, transparent: true } );
            
            var back = new THREE.Mesh( geometry, meterial );

            back.position.x = px;
            back.position.y = py + h / 2 + 1;
            back.position.z = pz - d / 2 + 2;
            
            back.hover = function(o) {
              hoverCabinet(o.container);
            }
            back.container = cabinet;

            targetList.push(back);
            scene.add(back);
            cabinet.back = back;
          
            // 机柜的左、右
            var geometry = new THREE.BoxGeometry(w, h, 2);
            var meterial = new THREE.MeshBasicMaterial( { color: 0x777777, opacity: 0.9, transparent: true } );
            
            var left = new THREE.Mesh( geometry, meterial );
            var right = new THREE.Mesh( geometry, meterial );
            
            left.position.x = px + w / 2 -1;
            left.position.y = py + h / 2 + 1;
            left.position.z = pz;
            left.rotation.y = Math.PI / 2;

            right.position.x = px - w / 2 +1;
            right.position.y = py + h / 2 + 1;
            right.position.z = pz;
            right.rotation.y = -Math.PI / 2;
            
            left.hover = function(o) {
              hoverCabinet(o.container);
            }
            left.container = cabinet;
            right.hover = function(o) {
              hoverCabinet(o.container);
            }
            right.container = cabinet;

            targetList.push(left);
            targetList.push(right);
            scene.add(left);
            scene.add(right);
            
            cabinet.left = left;
            cabinet.right = right;
            
            // 机柜的底部、顶部
            var geometry = new THREE.BoxGeometry(w, 2, d);
            var meterial = new THREE.MeshBasicMaterial( { color: 0x222222, transparent: true } );
            
            var top = new THREE.Mesh( geometry, meterial );
            var bottom = new THREE.Mesh( geometry, meterial );
            
            top.position.x = px;
            top.position.y = py + h + 2;
            top.position.z = pz;
            
            bottom.position.x = px;
            bottom.position.y = py + 2;
            bottom.position.z = pz;
            
            top.hover = function(o) {
              hoverCabinet(o.container);
            }
            top.container = cabinet;
            bottom.hover = function(o) {
              hoverCabinet(o.container);
            }
            bottom.container = cabinet;
            
            targetList.push(top);
            targetList.push(bottom);
            scene.add(top);
            scene.add(bottom);
            
            cabinet.top = top;
            cabinet.bottom = bottom;
            
            // 机柜门
            var geometry = new THREE.BoxGeometry(w, h, 2);
            var meterial = new THREE.MeshBasicMaterial( { color: 0x003333, opacity: 0.5, transparent: true } );
            
            var front = new THREE.Mesh( geometry, meterial );
            
            front.position.x = px;
            front.position.y = py + h / 2 + 1;
            front.position.z = pz + d / 2;
            front.toggle = function(o) {
              if ( o.rotation.y == 0 ) {
                o.rotation.y = o.rotation.y + Math.PI * 3 / 5;
                o.position.x = o.position.x + w / 2 + 3;
                o.position.z = o.position.z + d / 2;
                
                openCabinet(o.container);
              } else {
                o.rotation.y = o.rotation.y - Math.PI * 3 / 5;
                o.position.x = o.position.x - w / 2 - 3;
                o.position.z = o.position.z - d / 2;
                
                // 关闭机柜门时，将机柜中的服务器收起
                for (var i=0; i<o.container.servers.length; i++) {
                  o.container.servers[i].toggle(o.container.servers[i], false);
                }
                
                closeCabinet(o.container);
              }
            }
            front.hover = function(o) {
              hoverCabinet(o.container);
            }
            front.container = cabinet;
            
            scene.add(front);
            targetList.push(front);
            
            cabinet.front = front;
            
            // 
            cabinet.servers = [];

            if (c && c.servers) {
              cabinet.info = c;
              for (var i=0; i<c.servers.length; i++) {
                var server = createServer(w-4, 4, d-4, px, py + (9*(i+1)), pz+2);   // 服务器的厚度默认为 4， 服务器之间的间隔为 5
                server.container = cabinet;
                server.info = c.servers[i];
                cabinet.servers.push(server);
              }
            }
            
            return cabinet;
          }
          
          function createServer(w, h, d, px, py, pz) {
            // 服务器
            //var texture = new THREE.ImageUtils.loadTexture( '' );
            var texture = new THREE.ImageUtils.loadTexture( '../images/server.png' );
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping; 
            texture.repeat.set( 1, 1 );

            var texture_back = new THREE.ImageUtils.loadTexture( '../images/server-back.png' );
            texture_back.wrapS = texture_back.wrapT = THREE.RepeatWrapping; 
            texture_back.repeat.set( 1, 1 );

            var geometry = new THREE.BoxGeometry(w, h, d);
            //var material = new THREE.MeshBasicMaterial( { map: texture } );
            // Create an array of materials to be used in a cube, one for each side
            var materialArray = [];
            // order to add materials: x+,x-,y+,y-,z+,z-
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { map: texture } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { map: texture_back } ) );
            var material = new THREE.MeshFaceMaterial( materialArray );

            var server = new THREE.Mesh( geometry, material );
            
            server.position.x = px;
            server.position.y = py;
            server.position.z = pz;
            
            server.toggle = function(o, openOrClose) {
              // 关闭同一机柜中的其他服务器
              for (var i=0; i<o.container.servers.length; i++) {
                if ( o === o.container.servers[i] ) continue;
                if ( o.container.servers[i].position.z == pz ) {
                } else {
                  o.container.servers[i].position.z = o.container.servers[i].position.z - d / 2;
                  // 
                  closeServer(o.container.servers[i]);
                }
              }
              
              if ( o.position.z == pz ) {
                if ( openOrClose == null || openOrClose ) {
                  o.position.z = o.position.z + d / 2;
                  // 打开服务器时，处理其他逻辑
                  openServer(o);
                }
              } else {
                if ( openOrClose == null || !openOrClose ) {
                  o.position.z = o.position.z - d / 2;
                  // 关上服务器时，处理其他逻辑
                  closeServer(o);
                }
              }
            }
            server.hover = function(o) {
              hoverServer(o);
            }
            
            scene.add(server);
            targetList.push(server);
            
            return server;
          }
          
          function createDevice(w, h, d, px, py, pz, info) {
            var texture = new THREE.ImageUtils.loadTexture( '' );
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping; 
            texture.repeat.set( 1, 1 );
            
            var geometry = new THREE.BoxGeometry(w, h, d);
            //var material = new THREE.MeshBasicMaterial( { map: texture } );
            // Create an array of materials to be used in a cube, one for each side
            var materialArray = [];
            // order to add materials: x+,x-,y+,y-,z+,z-
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { map: texture } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            var material = new THREE.MeshFaceMaterial( materialArray );

            var dev = new THREE.Mesh( geometry, material );
            
            dev.position.x = px;
            dev.position.y = py;
            dev.position.z = pz;
            
            scene.add(dev);
            targetList.push(dev);
            
            dev.info = info;
            
            // 
            var geometry2 = new THREE.BoxGeometry(w+2, h+1, d+2);
            var meterial2 = new THREE.MeshBasicMaterial( { color: info.color, opacity: 0.6, transparent: true } );
            
            var dev_out = new THREE.Mesh( geometry2, meterial2 );
            dev_out.position.x = px;
            dev_out.position.y = py;
            dev_out.position.z = pz;
            
            scene.add(dev_out);
            
            return dev;
          }
          
          function createStandAir(w, h, d, px, py, pz) {
            var texture = new THREE.ImageUtils.loadTexture( '' );
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping; 
            texture.repeat.set( 1, 1 );
            
            var geometry = new THREE.BoxGeometry(w, h, d);
            //var material = new THREE.MeshBasicMaterial( { map: texture } );
            // Create an array of materials to be used in a cube, one for each side
            var materialArray = [];
            // order to add materials: x+,x-,y+,y-,z+,z-
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { map: texture } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            var material = new THREE.MeshFaceMaterial( materialArray );

            var air = new THREE.Mesh( geometry, material );
            
            air.position.x = px;
            air.position.y = py;
            air.position.z = pz;
            
            scene.add(air);
            targetList.push(air);
            
            return air;
          }
          
          function createFloor(width, height) {
            // FLOOR
            var floorGeometry = new THREE.PlaneGeometry(width, height);
            var floorMaterial = new THREE.MeshBasicMaterial( { color: 0xcccccc, side: THREE.DoubleSide } );
            var floor = new THREE.Mesh(floorGeometry, floorMaterial);
            //floor.position.x = 0;
            //floor.position.y = 0;
            //floor.position.z = 0;
            
            floor.rotation.x = Math.PI / 2;

            scene.add(floor);
            targetList.push(floor);
            
            return floor;
          }
          function createWall(w, h, px, py, pz, rx, ry, rz) {
            var wallTexture = new THREE.ImageUtils.loadTexture( '' );
            wallTexture.wrapS = wallTexture.wrapT = THREE.RepeatWrapping; 
            wallTexture.repeat.set( w / 20, h / 20 );

            var wallGeometry = new THREE.BoxGeometry(w, h, 5);
            var wallMaterial = new THREE.MeshBasicMaterial( { map: wallTexture, side: THREE.DoubleSide } );
            var wall = new THREE.Mesh( wallGeometry, wallMaterial );
            wall.position.x = px;
            wall.position.y = py;
            wall.position.z = pz;
            
            wall.rotation.y = ry;
            
            scene.add(wall);
            targetList.push(wall);
            
            return wall;
          }
          function createGlassWall(w, h, px, py, pz, rx, ry, rz) {
            var geometry = new THREE.BoxGeometry(w, h, 2);
            var meterial = new THREE.MeshBasicMaterial( { color: 0x003333, opacity: 0.4, transparent: true, side: THREE.DoubleSide } );
            var glassW = new THREE.Mesh( geometry, meterial );
            
            glassW.position.x = px;
            glassW.position.y = py;
            glassW.position.z = pz;
            
            glassW.rotation.y = ry;
            
            scene.add(glassW);
            targetList.push(glassW);
            
            return glassW;
          }
          function createColumn(w, h, px, py, pz) {
            var geometry = new THREE.BoxGeometry(w, h, w);
            var meterial = new THREE.MeshBasicMaterial( { color: 0xffffff, opacity: 1, transparent: true, side: THREE.DoubleSide } );
            var column = new THREE.Mesh( geometry, meterial );
            
            column.position.x = px;
            column.position.y = py;
            column.position.z = pz;
            
            scene.add(column);
            targetList.push(column);
            
            return column;
          }
          function createDoor(w, h, px, py, pz, rx, ry, rz) {
            var texture = new THREE.ImageUtils.loadTexture( '' );
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            texture.repeat.set( w / 50, w / 50 );
            
            var geometry = new THREE.BoxGeometry(w, h, 3);
            var material = new THREE.MeshBasicMaterial( { map: texture, side: THREE.DoubleSide } );
            var door = new THREE.Mesh( geometry, material );
            door.position.x = px;
            door.position.y = py;
            door.position.z = pz;
            
            scene.add(door);
            targetList.push(door);
            
            return door;
          }
          function createWindow(w, h, px, py, pz, rx, ry, rz) {
            var geometry = new THREE.PlaneGeometry(w, h);
            var meterial = new THREE.MeshBasicMaterial( { color: 0x00fff0, opacity: 0.5, transparent: true, side: THREE.DoubleSide } );
            var windw = new THREE.Mesh( geometry, meterial );
            
            windw.position.x = px;
            windw.position.y = py;
            windw.position.z = pz;
            
            scene.add(windw);
            targetList.push(windw);
            
            return windw;
          }
          
          function createFireExtinguisher(w, h, px, py, pz) {
            var texture = new THREE.ImageUtils.loadTexture( '' );
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            texture.repeat.set( 1, 1 );
            
            //var geometry = new THREE.BoxGeometry(w, h, w);
            var geometry = new THREE.CylinderGeometry( w, w, h, 20, 4 );
            //var material = new THREE.MeshBasicMaterial( { map: texture } );
            
            var materialArray = [];
            materialArray.push( new THREE.MeshBasicMaterial( { map: texture } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            materialArray.push( new THREE.MeshBasicMaterial( { color: 0xbbbbbb } ) );
            var material = new THREE.MeshFaceMaterial( materialArray );
            
            var fe = new THREE.Mesh( geometry, material );
            fe.position.x = px;
            fe.position.y = py;
            fe.position.z = pz;
            
            scene.add(fe);
            targetList.push(fe);
            
            //return fe;

            var geometry = new THREE.SphereGeometry( w, 32, 16, 0, 2 * Math.PI, 0, Math.PI / 2 );
            var material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
            var fe = new THREE.Mesh( geometry, material );
            fe.position.x = px;
            fe.position.y = py + h / 2;
            fe.position.z = pz;
            
            scene.add(fe);
            targetList.push(fe);

            var geometry = new THREE.CylinderGeometry( 3, 3, 5, 20, 4 )
            var material = new THREE.MeshBasicMaterial( { color: 0x000000 } );
            var fe = new THREE.Mesh( geometry, material );
            fe.position.x = px;
            fe.position.y = py + h / 2 + w;
            fe.position.z = pz;
            
            scene.add(fe);
            targetList.push(fe);
            
          }
          
          function onDocumentMouseMove( event ) {
            // the following line would stop any other event handler from firing
            // (such as the mouse's TrackballControls)
            // event.preventDefault();

            // update the mouse variable
            mouse.x = ( event.clientX / SCREEN_WIDTH ) * 2 - 1;
            mouse.y = - ( event.clientY / SCREEN_HEIGHT ) * 2 + 1;
            
            // find intersections

            // create a Ray with origin at the mouse position
            //   and direction into the scene (camera direction)
            var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
            projector.unprojectVector( vector, camera );
            var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );

            // create an array containing all objects in the scene with which the ray intersects
            var intersects = ray.intersectObjects( targetList );

            // if there is one (or more) intersections
            if ( intersects.length > 0 )
            {
              //console.log("Hit @ " + toString( intersects[0].point ) );
              // change the color of the closest face.
              //intersects[ 0 ].face.color.setRGB( 0.8 * Math.random() + 0.2, 0, 0 ); 
              //intersects[ 0 ].object.geometry.colorsNeedUpdate = true;

              var o = intersects[ 0 ].object;
              if (typeof o.hover == 'function') {
                o.hover(o);
              } else {
                closeHover();
              }
            }
          }
          
          function onDocumentMouseDown( event ) 
          {
            // the following line would stop any other event handler from firing
            // (such as the mouse's TrackballControls)
            // event.preventDefault();

            //console.log("Click.");

            // update the mouse variable
            mouse.x = ( event.clientX / SCREEN_WIDTH ) * 2 - 1;
            mouse.y = - ( event.clientY / SCREEN_HEIGHT ) * 2 + 1;

            // find intersections

            // create a Ray with origin at the mouse position
            //   and direction into the scene (camera direction)
            var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
            projector.unprojectVector( vector, camera );
            var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );

            // create an array containing all objects in the scene with which the ray intersects
            var intersects = ray.intersectObjects( targetList );

            // if there is one (or more) intersections
            if ( intersects.length > 0 )
            {
                //console.log("Hit @ " + toString( intersects[0].point ) );
                // change the color of the closest face.
                //intersects[ 0 ].face.color.setRGB( 0.8 * Math.random() + 0.2, 0, 0 ); 
                //intersects[ 0 ].object.geometry.colorsNeedUpdate = true;

                var o = intersects[ 0 ].object;
                if (typeof o.toggle == 'function') {
                  o.toggle(o);
                }
            }
          }
          
          function toString(v) { return "[ " + v.x + ", " + v.y + ", " + v.z + " ]"; }

          function animate() 
          {
              requestAnimationFrame( animate );
              render();		
              update();
          }

          function update()
          {
            keyboard.update();

            var moveDistance = 50 * clock.getDelta(); 

            if ( keyboard.pressed("left") || keyboard.pressed("A") ) 
              camera.translateX( -5 );

            if ( keyboard.pressed("right") || keyboard.pressed("D") ) 
              camera.translateX(  5 );
            
            if ( keyboard.pressed("up") || keyboard.pressed("W") ) 
              camera.translateZ( -5 );

            if ( keyboard.pressed("down") || keyboard.pressed("S") ) 
              camera.translateZ(  5 );

            if ( keyboard.pressed("R") ) 
              camera.translateY( -5 );

            if ( keyboard.pressed("F") ) 
              camera.translateY(  5 );
            
            if ( keyboard.pressed("Q") )
              controls.pan( new THREE.Vector3( -10, 0, 0 ) );

            if ( keyboard.pressed("E") )
              controls.pan( new THREE.Vector3(  10, 0, 0 ) );

            /*
            if ( keyboard.down("R") )
              mesh.material.color = new THREE.Color(0xff0000);
            if ( keyboard.up("R") )
              mesh.material.color = new THREE.Color(0x0000ff);
            */
            
            controls.update();
            stats.update();
          }

          function render() 
          {
              renderer.render( scene, camera );
          }
		</script>
	</body>
</html>
